package com.andy.android.serialporttest;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.widget.Toast;

import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

public class H10BManager {

    private static H10BManager INSTANCE;

    private static final String TAG = "";

    private Context context;


    private boolean isReading = false;
    private final Object inLock = new Object(), outLock = new Object();
    private UsbManager usbManager;  //USB管理器:负责管理USB设备的类
    private UsbDevice usbDevice;   //找到的USB设备
    private UsbInterface usbInterface;  //代表USB设备的一个接口
    private UsbDeviceConnection deviceConnection;  //USB连接的一个类。用此连接可以向USB设备发送和接收数据，
    private UsbEndpoint usbEpIn;  //代表一个接口的某个节点的类:读数据节点
    private UsbEndpoint usbEpOut;  //代表一个接口的某个节点的类:写数据节点

    //private final int VID = 1155;
    //private final int PID = 22352;
    private int VID;
    private int PID;
    private String mSerialNum = "";

    //ceshi
    public static boolean issendok = false;
    private int h10b_status = 0;
    //高精度
    private String GGA_Temp;

    private String GGA_temp = "";
    private String GGA_buf = "";
    private String RMC_temp = "";
    private String RMC_buf = "";
    private String GGA_temp2 = "";
    private String GGA_buf2 = "";
    private String GGA_data = "";
    private String RMC_data = "";

    public static boolean GGA_start = false;
    //纬度
    private double gga_latitued;
    //经度
    private double gga_lngitued;
    //状态
    private int gga_locMode;
    //卫星
    private int gga_satelliteNum;
    //HDOP
    private float gga_hdop;
    //高度
    private float gga_altitude;

    private double rmc_speed;

    private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";

    public static int h10b_ctrl_flag = 0;
    private int flag = 0;

    private boolean qx_start = false;

    NormalBean normalBean;

    private LocalBroadcastManager h10bLbm;

    /**
     * H10BGPS坐标点
     */
    private List<LatLng> H10BLatLngs = new ArrayList<>();// position

    //list启动标志  List_Flag = 1 启动
    private int List_Flag = 0;

    private H10BManager(Context context) {
        INSTANCE = this;
        this.context = context;
//        mAppInstance = null; // todo needs to init
        normalBean = new NormalBean();
    }

    public static H10BManager getINSTANCE(Context context) {
        if (INSTANCE == null) {
            INSTANCE = new H10BManager(context);
        }
        return INSTANCE;
    }

    public void initUsbDevice() {
        Log.d(TAG, "initUsbDevice E");
        h10b_ctrl_flag = 0;
        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
        if (usbManager == null) {
            Log.d(TAG, "usbManager == null");
            return;
        } else {
            Log.d(TAG, "usbManager != null");
            HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
            if (!deviceList.isEmpty()) {
                Log.d(TAG, "!deviceList.isEmpty()");
                Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
                while (deviceIterator.hasNext()) {
                    UsbDevice device = deviceIterator.next();
                    VID = device.getVendorId();
                    PID = device.getProductId();
                    Log.d(TAG, "VID = " + VID + "---PID = " + PID);
//                    mSerialNum = device.getSerialNumber();  //获取设备序列号
                    if (VID == 1155 && PID == 22352) {
                        usbDevice = device;
                        StatusManager.isConnected = true;
//                        mAppInstance.setUsbConnected(true);
                        getDeviceInterface();
                    }
                }
            } else {
//                mAppInstance.setUsbConnected(false);
                StatusManager.isConnected = false;
                Log.d(TAG, "Not Find the device");
            }
        }
        Log.d(TAG, "initUsbDevice X");
    }

    private void getDeviceInterface() {
        Log.d(TAG, "getDeviceInterface E");
        if (usbDevice != null) {
            Log.d(TAG, "usbDevice != null");
            for (int i = 0; i < usbDevice.getInterfaceCount(); i++) {
                UsbInterface intf = usbDevice.getInterface(i);
                if (intf.getInterfaceClass() == 3 && intf.getInterfaceSubclass() == 0 && intf.getInterfaceProtocol() == 0) {
                    usbInterface = intf;
                    openDevice();
                }
                break;
            }
        } else {
            Toast.makeText(context, "Not find the device", Toast.LENGTH_SHORT).show();
        }
        Log.d("TAG", "getDeviceInterface X");
    }

    private void openDevice() {
        Log.d("TAG", "openDevice E");
        if (usbInterface != null) {
            Log.d("TAG", "usbInterface != null");
            UsbDeviceConnection conn = null;

            if (!usbManager.hasPermission(usbDevice)) {
                Log.d("TAG", "没有权限-1");
                PendingIntent pi = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                usbManager.requestPermission(usbDevice, pi);
            }
            if (usbManager.hasPermission(usbDevice)) {
                Log.d("TAG", "有权限");
                conn = usbManager.openDevice(usbDevice);
            } else {
                Log.d("TAG", "没有权限-2");
//                mAppInstance.setIsoncl(false);
                StatusManager.isOnCtl = false;
                Toast.makeText(context, "No permission", Toast.LENGTH_SHORT).show();
            }
            if (conn == null) {
                Log.d("TAG", "conn == null");
//                mAppInstance.setIsoncl(false);
                StatusManager.isOnCtl = false;
                return;
            }
            if (conn.claimInterface(usbInterface, true)) {
                Log.d("TAG", "conn.claimInterface = ture");
                deviceConnection = conn;
                if (deviceConnection != null) {
//                    mAppInstance.setIsoncl(true);
                    StatusManager.isOnCtl = true;

                    assignEndpoint();
                }
            } else {
                conn.close();
//                mAppInstance.setIsoncl(false);
                StatusManager.isOnCtl = false;

            }
        }
        Log.d("TAG", "openDevice X");
    }

    private void assignEndpoint() {
        Log.d("TAG", "assignEndpoint E");
        if (usbInterface != null) {

            for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                UsbEndpoint ep = usbInterface.getEndpoint(i);
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                        usbEpIn = ep;
                    } else {
                        usbEpOut = ep;
                    }
                }
                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_INT) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                        usbEpIn = ep;
                    } else {
                        usbEpOut = ep;
                    }
                }
            }

            if (usbEpIn != null) {
                //初始化H10B
                int send_result = h10b_start();
                if (send_result > 0) {
                    StartReading();
                }
            }
        }
        Log.d("TAG", "assignEndpoint X");
    }

    public void StartReading() {
        Log.d("TAG", "StartReading");
        deviceConnection.claimInterface(usbInterface, true);

        isReading = true;

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (isReading) {
                    try {
                        byte[] recvbytes = new byte[usbEpIn.getMaxPacketSize()];
                        int recv_result = deviceConnection.bulkTransfer(usbEpIn, recvbytes, recvbytes.length, 1000);
                        byte[] tempReadData = null;
                        if (recv_result > 0) {
                            tempReadData = Arrays.copyOf(recvbytes, recv_result);
                        }
                        final byte[] readData = tempReadData;
                        String s = Util.convertHexToString(Util.byte2hex(readData));
                        Log.d(TAG, "read : " + s);
                        Datanalysis(s);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    //判断H10B接收包
    private int CountStr(String str1, String str2) {
        int index = 0;
        int count = 0;
        while ((index = str1.indexOf(str2, index)) != -1) {
            index = index + str2.length();
            count++;
        }
        return count;
    }

    //数据解析
    private void Datanalysis(String s) {
        Log.d("TAG", "Datanalysis : " + s);
        try {
            //判断是否是高低精度
            //判断H10B接收包是否包含@
            if (h10b_ctrl_flag == 0) {
                if (s.indexOf("TD") > 0) {
                    flag = 1;
                    h10b_ctrl_flag = 1;
                    //低精度
                    h10b_status = 1;
                    h10b_stop();
                    StatusManager.h10b_status_d = true;

                }
                if (s.indexOf("QX") > 0) {
                    flag = 2;
                    h10b_ctrl_flag = 2;
                    //高精度
                    h10b_status = 2;
                    h10b_stop();
                    StatusManager.use_dialog_flag_g = true;
                }
            }
            if (h10b_ctrl_flag == 1) {
                if (CountStr(s, "@") > 0 && CountStr(s, "$GNRMC") > 0 && CountStr(s, "$GNGGA") > 0) {
                    RMC_data = s.substring(s.indexOf("$GNRMC"), s.indexOf("$GNGGA"));
                    GGA_data = s.substring(s.indexOf("$GNGGA"));
                }
                //完整数据包含RMC GGA
                //先判断标志位是否存在，再判断RMC是否存在，判断结束符是否不存在，判断GGA是否不存在
                if (CountStr(s, "@") > 0 && CountStr(s, "$GNRMC") > 0 && CountStr(s, "@") > 0 && CountStr(s, "\r\n") == 0 && CountStr(s, "$GNGGA") == 0) {
                    RMC_temp = s.substring(s.indexOf("$GNRMC"));
                }
                //先判断标志位是否不存在，再判断RMC是否不存在，判断结束符是否存在，判断GGA是否存在
                if (CountStr(s, "@") == 0 && CountStr(s, "$GNRMC") == 0 && CountStr(s, "\r\n") > 0 && CountStr(s, "$GNGGA") > 0) {//rmc后端 和GGA前端
                    RMC_buf = s.substring(0, s.indexOf("\r\n"));
                    RMC_data = RMC_temp + RMC_buf;
                    GGA_temp2 = s.substring(s.indexOf("$GNGGA"));
                }

                if (CountStr(s, "@") == 0 && CountStr(s, "$GNGGA") == 0 && CountStr(s, "\r\n") > 0 && CountStr(s, "$GNRMC") == 0) {//GGA后端
                    GGA_buf2 = s.substring(0, s.indexOf("\r\n"));
                    GGA_data = GGA_temp2 + GGA_buf2;
                    Log.d("TAG", "H10B_D_GGA:GGA_data = " + GGA_data);
                    GetGGA_RMC(GGA_data, RMC_data);
                }
            }
            if (h10b_ctrl_flag == 2) {
                //一包64个数据既有RMC 又有GGA 数据不完整
                if (CountStr(s, "@") > 0 && CountStr(s, "$GNRMC") > 0 && CountStr(s, "$GNGGA") > 0) {
                    RMC_data = s.substring(s.indexOf("$GNRMC"), s.indexOf("$GNGGA"));
                    GGA_data = s.substring(s.indexOf("$GNGGA"));
                }
                //完整数据包含RMC GGA
                //先判断标志位是否存在，再判断RMC是否存在，判断结束符是否不存在，判断GGA是否不存在
                if (CountStr(s, "@") > 0 && CountStr(s, "$GNRMC") > 0 && CountStr(s, "@") > 0 && CountStr(s, "\r\n") == 0 && CountStr(s, "$GNGGA") == 0) {
                    RMC_temp = s.substring(s.indexOf("$GNRMC"));
                }
                //先判断标志位是否不存在，再判断RMC是否不存在，判断结束符是否存在，判断GGA是否存在
                if (CountStr(s, "@") == 0 && CountStr(s, "$GNRMC") == 0 && CountStr(s, "\r\n") > 0 && CountStr(s, "$GNGGA") > 0) {//rmc后端 和GGA前端
                    RMC_buf = s.substring(0, s.indexOf("\r\n"));
                    RMC_data = RMC_temp + RMC_buf;
                    GGA_temp2 = s.substring(s.indexOf("$GNGGA"));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            Log.d(TAG, e.getMessage());
        }
    }

    public void GetGGA_RMC(String GGA, String RMC) {
        Log.d("TAG", "GetGGA_RMC");

        Log.d(TAG, "GetGGA_RMC: GGA : " + GGA + "  RMC : " + RMC);

        String[] buf1 = RMC.split(",");
        if (buf1[7] != null) {
            rmc_speed = Util.rmc_speed(Double.parseDouble(buf1[7]));
        }


        String[] buf = GGA.split(",");

        if (buf[2] != null && buf[3] != null && buf[4] != null && buf[5] != null) {
//            //纬度
            gga_latitued = Util.LatAnalysis(buf[2], buf[3]);
//            //经度
            gga_lngitued = Util.LngAnalysis(buf[4], buf[5]);

            //模式
            gga_locMode = Integer.parseInt(buf[6]);
            //卫星数
            gga_satelliteNum = Integer.parseInt(buf[7]);
            //HDOP
            gga_hdop = Float.parseFloat(buf[8]);
            //高度
            gga_altitude = Float.parseFloat(buf[9]);
        }

        Log.d(TAG, "alti : " + gga_altitude + "lat : " + gga_latitued + " lng : " + gga_lngitued + "  mode : " + gga_locMode + "  sat_num : " + gga_satelliteNum + "  HDOP: " + gga_hdop);

    }


    /**
     * 数据发送方法，尽量在非主线程中进行
     *
     * @param data
     * @param dataLength
     */
    public int writeData(byte[] data, int dataLength) {
        synchronized (outLock) {
            if (deviceConnection != null && usbEpOut != null) {
                int writeResult = deviceConnection.bulkTransfer(usbEpOut, data, dataLength, 1000);
                if (writeResult >= 0) {
                    //T.showShort(context, context.getString(R.string.write_h10b_suess)+ ":" + writeResult);
                } else {
                    Toast.makeText(context, "write result failed : " + writeResult, Toast.LENGTH_SHORT).show();
                }
                return writeResult;
            } else {
                return -99;
            }
        }
    }

    //启动h10b
    public int h10b_start() {
        byte[] send = h10b_start_com();
        int send_result = writeData(send, send.length);
        Log.d(TAG, "start result : " + send_result);
        return send_result;
    }

    private byte[] h10b_start_com() {
        //发送H10B启动命令
        byte[] send_start = new byte[12];
        send_start[0] = (byte) 0x48;//H
        send_start[1] = (byte) 0x31;//1
        send_start[2] = (byte) 0x30;//0
        send_start[3] = (byte) 0x42;//B
        send_start[4] = (byte) 0x3A;//:
        send_start[5] = (byte) 0x43;//C
        send_start[6] = (byte) 0x4F;//O
        send_start[7] = (byte) 0x4E;//N
        send_start[8] = (byte) 0x4E;//N
        send_start[9] = (byte) 0x45;//E
        send_start[10] = (byte) 0x43;//C
        send_start[11] = (byte) 0x54;//T
        return send_start;
    }

    //断开h10b
    public void h10b_stop() {
        byte[] send = h10b_stop_com();
        int send_result = writeData(send, send.length);
        Log.d(TAG, "stop result : " + send_result);
    }

    private byte[] h10b_stop_com() {
        //发送H10B启动命令
        byte[] send_stop = new byte[15];
        send_stop[0] = (byte) 0x48;//H
        send_stop[1] = (byte) 0x31;//1
        send_stop[2] = (byte) 0x30;//0
        send_stop[3] = (byte) 0x42;//B
        send_stop[4] = (byte) 0x3A;//:
        send_stop[5] = (byte) 0x44;//D
        send_stop[6] = (byte) 0x49;//I
        send_stop[7] = (byte) 0x53;//S
        send_stop[8] = (byte) 0x43;//C
        send_stop[9] = (byte) 0x4F;//O
        send_stop[10] = (byte) 0x4E;//N
        send_stop[11] = (byte) 0x4E;//N
        send_stop[12] = (byte) 0x45;//E
        send_stop[13] = (byte) 0x43;//C
        send_stop[14] = (byte) 0x54;//T

        return send_stop;
    }

    public int H10B_Status() {
        return h10b_status;
    }

    public void stop() {
        isReading = false;
    }

    public void start() {
        isReading = true;
    }

}